﻿using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.Routing;
using Inovout.Data.Domain;

namespace System.Web.Mvc
{
    public static class QueryCriteriaHelper
    {
        public static readonly string DefaultQueryCriterionKey = ViewDataDictionaryExtensions.AdditionalViewDataKeyPrefix + "QueryCriterion";
        public static readonly string DefaultFilterCriterionsKey = ViewDataDictionaryExtensions.AdditionalViewDataKeyPrefix + "FiterCriterions";
        public static readonly string DefaultOrderCriterionsKey = ViewDataDictionaryExtensions.AdditionalViewDataKeyPrefix + "OrderCriterions";
    
        public static readonly char Separator = '|';
        public static readonly string RequestQueryFilterKey = "_f";
        public static readonly string RequestQueryOrderKey = "_o";
        public static QueryCriteria Parse(Type modelType, IValueProvider valueProvider)
        {
            QueryCriteria queryCriteria = new QueryCriteria(modelType);
            var valueResult = valueProvider.GetValue(RequestQueryFilterKey);
            if (valueResult != null)
            {
                queryCriteria.Filters = ParseFilter(valueResult.AttemptedValue).ToList();
            }
            valueResult = valueProvider.GetValue(RequestQueryOrderKey);
            if (valueResult != null)
            {
                queryCriteria.Orders = ParseOrder(valueResult.AttemptedValue).ToList();
            }
            return queryCriteria;
        }
        public static FilterCriteria[] ParseFilter(string filter)
        {
            string[] filterArray = filter.Split(Separator);
            FilterCriteria[] filterCriteria = new FilterCriteria[filterArray.Length / 3];
            for (int i = 0; i < filterCriteria.Length; i++)
            {
                int index = i * 3;
                filterCriteria[i] = new FilterCriteria(filterArray[index],
                    (FilterOperation)int.Parse(filterArray[index + 1]), filterArray[index + 2]);
            }
            return filterCriteria;
        }
        private static OrderCriteria[] ParseOrder(string order)
        {
            string[] orderArray = order.Split(Separator);
            int count=orderArray.Length / 2;
            OrderCriteria[] orderCriteria = new OrderCriteria[count];
            for (int i = 0; i < orderCriteria.Length; i++)
            {
                int index = i * 2;
                orderCriteria[i] = new OrderCriteria(orderArray[index],
                    Convert.ToBoolean(orderArray[index + 1]));
            }
            return orderCriteria;
        }
        private static readonly string FilterStringFormat = "{1}{0}{2}{0}{3}";
        private static readonly string OrderStringFormat = "{1}{0}{2}";
        public static RouteValueDictionary BuildRouteDictionary(QueryCriteria queryCriteria, RouteValueDictionary routes, string property = null, bool? asc = null)
        {
            routes = routes ?? new RouteValueDictionary();
            string route = GetFilterString(queryCriteria.Filters);
            if (!string.IsNullOrEmpty(route))
            {
                routes.Add(RequestQueryFilterKey, route);
            }
            route = GetOrderString(queryCriteria.Orders, property, asc);
            if (!string.IsNullOrEmpty(route))
            {
                routes.Add(RequestQueryOrderKey, route);
            }
            return routes;
        }
        public static string GetFilterString(IEnumerable<FilterCriteria> filters)
        {
            StringBuilder sb = new StringBuilder();
            foreach (var filter in filters)
            {
                if (sb.Length > 0)
                {
                    sb.Append(Separator);

                }
                sb.Append(string.Format(FilterStringFormat, Separator, filter.FilterName,
                    Convert.ToString((int)filter.FilterOperation), filter.FilterValue));
            }


            return sb.ToString();
        }
        public static string GetOrderString(IEnumerable<OrderCriteria> orders, string property = null, bool? asc = null)
        {
            StringBuilder sb = new StringBuilder();
            foreach (var order in orders)
            {
                if (sb.Length > 0)
                {
                    sb.Append(Separator);

                }
                if (!string.IsNullOrEmpty(property) && order.OrderName.Equals(property))
                {
                    bool result = asc.HasValue ? asc.Value : !order.OrderAscending;
                    sb.Append(string.Format(OrderStringFormat, Separator, order.OrderName,
                        Convert.ToString(result)));
                }
                else
                {
                    sb.Append(string.Format(OrderStringFormat, Separator, order.OrderName,
                        Convert.ToString(order.OrderAscending)));
                }
            }


            return sb.ToString();
        }
    }
}
